from typing import Dict, Tuple, Union
from glob import glob
import os
import importlib
import traceback
import sys

from pluginUtils import BasicComprehensionPlugin, BasicReaderPlugin
from pymodels.utils.BookReader import MixBookReader


def get_comprehensioner(config) -> Dict[str, BasicComprehensionPlugin]:
    _plugins = dict()
    for modulename in glob("plugins/comprehensioner/*"):
        _, modulename = os.path.split(modulename)
        if modulename[0] == '_':
            continue
        k, v = load_comprehensioner(config, modulename)
        _plugins[k] = v

    return _plugins


def load_comprehensioner(config, modulename):
    """
    根据配置，加载插件。
    :param config: json配置。
    :param modulename: 插件名称。
    :return: 成功构造对象，则返回（插件名称，对象）；否则返回（插件名称，类）
    """
    pluginname = modulename[:-3]
    modulename = "plugins.comprehensioner." + modulename[:-3]
    print("loading", modulename)
    pluginmodule = importlib.import_module(modulename, ".")
    try:
        ComprehensionPlugin = pluginmodule.ComprehensionPlugin  # noqa
    except AttributeError:
        print("无效的插件，未定义ComprehensionPlugin(BasicComprehensionPlugin)类。")
        return False
    if pluginname not in config['plugins']['comprehensioner']:
        config['plugins']['comprehensioner'][pluginname] = {
            "type": pluginname,
            "construct_params": {}
        }
    construct_params = config['plugins']['comprehensioner'][pluginname]['construct_params']
    try:
        comprehensionerplugin = ComprehensionPlugin(**construct_params)
        # _plugins[pluginname] = comprehensionerplugin
        return pluginname, comprehensionerplugin
    except TypeError as e:
        print("-" * 30, "无效的构造参数", "-" * 30)
        traceback.print_exc(file=sys.stdout)
        print("-" * 60)
        # 没有有效构造参数时，储存类，用于在插件配置页对参数进行配置。
        # _plugins[pluginname] = ComprehensionPlugin
        return pluginname, ComprehensionPlugin


def get_reader(config) -> Tuple[MixBookReader, Dict[str, BasicReaderPlugin]]:
    """
    加载阅读器插件。
    支持多类型映射。只需实现support_file_type方法，返回支持的文件类型集合即可。
    :param config:
    :return:
    """
    _readertype2pluginobject = dict()
    _reader = MixBookReader()
    for modulename in glob("plugins/reader/*"):
        _, modulename = os.path.split(modulename)
        pluginname = modulename[:-3]  # like `txt`
        support_file_type = '.' + pluginname
        # support_file_type = 可以将支持类型更改为类方法。
        if modulename[0] == '_':
            continue
        modulename = "plugins.reader." + modulename[:-3]
        print("loading", modulename)
        pluginmodule = importlib.import_module(modulename, ".")
        try:
            ReaderPlugin = pluginmodule.ReaderPlugin  # noqa
        except AttributeError:
            print("无效的插件，ReaderPlugin(BasicReaderPlugin)类。")
            continue
        if support_file_type not in config['plugins']['reader']:
            config['plugins']['reader'][support_file_type] = {
                "type": support_file_type,
                "construct_params": {}
            }
        construct_params = config['plugins']['reader'][support_file_type]['construct_params']
        try:
            readerplugin = ReaderPlugin(**construct_params)
            if hasattr(readerplugin, "support_file_type"):
                sfts = readerplugin.support_file_type()
                print("    support file type also to:", sfts)
                for sft in sfts:
                    _readertype2pluginobject[sft] = readerplugin
                    _reader.add(sft, readerplugin)
            _readertype2pluginobject[support_file_type] = readerplugin
            _reader.add(support_file_type, readerplugin)
        except TypeError:
            print("-" * 30, "无效的构造参数", "-" * 30)
            traceback.print_exc(file=sys.stdout)
            print("-" * 60)
            _readertype2pluginobject[support_file_type] = ReaderPlugin
    return _reader, _readertype2pluginobject


def get_reader_init_params(config, name):
    """
    返回既定reader插件的构造参数。
    :param config:
    :param name:
    :return:
    """
    return config["plugins"]["reader"][name]["construct_params"]
